package com.hzmg.akkacloud.worker.background;

import akka.cluster.Cluster;
import cn.hutool.core.lang.Console;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hzmg.akkacloud.common.model.ServiceInstance;
import com.hzmg.akkacloud.common.model.WorkerInfo;
import com.hzmg.akkacloud.common.utils.Meaningless;
import com.hzmg.akkacloud.worker.background.listener.ServicesListener;
import com.hzmg.akkacloud.worker.common.ThreadLocalStore;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * services management.
 *
 * @author zbw
 * @since 2022/8/7
 */
@Slf4j
public class ReactiveDiscoveryClient {
    // 存储Service健康信息，appName -> ServiceInstance
    private static final Map<String, ServiceInstance> appName2ServiceInstance = Maps.newConcurrentMap();
    //对Service健康信息的监听器 #废弃
    private static ServicesListener listener;

    /**
     * 更新状态
     * 新增：覆盖前先判断是否与原值相同，不相同的需先更新路由再覆盖原值。
     * 废弃新增
     *
     * @author zbw
     * @since 2022/9/4
     */
    public static void updateStatus(Map<String, ServiceInstance> serviceInstanceMap) {
        //更新时重复的会直接覆盖原值
        appName2ServiceInstance.putAll(serviceInstanceMap);
        //测试高可用。
        printIp2WorkInfo();
    }

    /**
     * 获取所有的worker信息 appId->Cluster
     */
    private static Map<String, ServiceInstance> getAppName2ServiceInstance() {
        return appName2ServiceInstance;
    }

    public static void printAppName2ServiceInstance() {
        appName2ServiceInstance.forEach((test, test2) -> {
            Console.log("[appName+service]" + test + ":" + test2.toString());
        });
    }

    private static void getServiceInstanceByAppNameTest() {

    }

    private static void printIp2WorkInfo() {
        appName2ServiceInstance.forEach((test, test2) -> test2.getAddress2WorkerInfo().forEach((s1, s2) -> {
            log.info(s2.toString());
        }));
    }

    /**
     * 通过appName获取该appName对应的worker集群
     */
    public static Map<String, WorkerInfo> getWorkerInfosByAppName(String appName) {
        ServiceInstance serviceInstance = getAppName2ServiceInstance().get(appName);
        if (serviceInstance == null) {
            //printAppName2ServiceInstance();
            log.error("[ReactiveDiscoveryClient] can't find any worker for app(appName={}).", appName);
            return Collections.emptyMap();
        }
        return serviceInstance.getAddress2WorkerInfo();
    }

    /**
     * get all alive workers
     *
     * @param appName appName
     * @return alive workers
     */
    public static List<WorkerInfo> getAllAliveWorkers(String appName) {
        List<WorkerInfo> workers = Lists.newArrayList(getWorkerInfosByAppName(appName).values());
        workers.removeIf(WorkerInfo::timeout);
        return workers;
    }

    /**
     * get all alive workers
     *
     * @param appName appName
     * @return alive workers
     */
    public static List<WorkerInfo> getAllWorkersWithAppName(String appName) {
        return Lists.newArrayList(getWorkerInfosByAppName(appName).values());
    }

    /**
     * run when receive the Instances
     * pay attention to thread safety
     */
    public void runWhenInstanceIsReceive(final Meaningless callback) {

        Cluster cluster = Cluster.get(ThreadLocalStore.getRuntimeMeta().getActorSystem());
        cluster.registerOnMemberUp(() -> {
            try {
                Thread.sleep(2000);
                callback.m();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}
